#!/usr/bin/python2.4


import cgi
import operator
import os
import time
import types

import constants
import rpc_stubs
from tag import Tag, tag
import test_stats as test_stats_module
import url
import utils


def create_list_table_div(rows):

  def is_sequence(value):
    return isinstance(value, (list, tuple, types.GeneratorType))

  def is_list_table(value):
    return (isinstance(value, dict) or
            (is_sequence(value) and value and
             is_sequence(value[0]) and len(value[0]) == 2))

  div = tag.div(class_='list_table_div')
  table = None
  if isinstance(rows, dict):
    rows = rows.iteritems()
  for name, value in rows:
    if not table:
      table = tag.table
      div += table
    if is_list_table(value):
      table += tag.tr(tag.th(name, ':'), tag.td, _s=True)
      div += create_list_table_div(value)
      table = None
    elif is_sequence(value):
      if value:
        value = ', '.join(str(v) for v in value)
      else:
        value = str(value)
      table += tag.tr(tag.th(name, ':', _s=True),
                      tag.td(cgi.escape(value), _s=True))
    elif isinstance(value, Tag):
      table += tag.tr(tag.th(name, ':', _s=True),
                      tag.td(value))
    elif isinstance(value, basestring) and value.startswith('\n'):
      table += tag.tr(tag.th(name, ':'), tag.td, _s=True)
      div += tag.pre(cgi.escape(value), _s=True)
      table = None
    else:
      table += tag.tr(tag.th(name, ':', _s=True),
                      tag.td(cgi.escape(str(value)), _s=True))
  return div


def create_tests_table_tr(test):
  ATTRIBUTES = ('job_name', 'control_type', 'duration', 'timeout',
                'synch_count', 'dependencies', 'path')
  tr = tag.tr
  if not test:
    for attr in ATTRIBUTES:
      tr += tag.th(attr.replace('_', ' ').title(), _s=True)
    tr += tag.th('Others', _s=True)
  else:
    for attr in ATTRIBUTES:
      value = getattr(test, attr)
      if attr == 'job_name':
        value = tag.a(value)
      elif attr == 'dependencies':
          value = ', '.join(sorted(value))
      td = tag.td(value, _s=True)
      if isinstance(value, (int, long, float)):
        td['align'] = 'right'
      elif attr == 'control_type':
        td['align'] = 'center'
      tr += td
    others = []
    for key, value in test.create_job_args.iteritems():
      if key != 'control_file' and key not in ATTRIBUTES:
        others.append('%s=%r' % (key, value))
    tr += tag.td(cgi.escape(', '.join(others)), _s=True)
  return tr


def create_tests_table(tests):
  table = tag.table(create_tests_table_tr(None), id='tests_table')
  for test in tests:
    table += create_tests_table_tr(test)
  return table


def create_test_list_table(test):
  ATTRIBUTES = ('job_name', 'path', 'duration', 'control_type', 'synch_count',
                'dependencies', 'timeout')
  list_table = []
  for attr in ATTRIBUTES:
    value = getattr(test, attr)
    if attr == 'duration' or attr == 'timeout':
      value = '%sh' % value
    list_table.append((attr.replace('_', ' ').title(), value))
  for key, value in test.create_job_args.iteritems():
    if key != 'control_file' and key not in ATTRIBUTES:
      list_table.append((key.replace('_', ' ').title(), value))
  list_table.append(('Control File', '\n%s' % test.control_file))
  return create_list_table_div(list_table)


def create_test_plan_list_table(test_plan, hosts, overall_duration):
  ATTRIBUTES = ('name', 'job_owners', 'email_list',
                'start_time', 'finish_time', 'check_config')
  list_table = []
  for attr in ATTRIBUTES:
    value = getattr(test_plan, attr)
    list_table.append((attr.replace('_', ' ').title(), value))
  stats = '%s tests' % len(test_plan.tests)
  if hosts is not None:
    stats += ' %s hosts' % len(hosts)
  if overall_duration is not None:
    hours, runs = overall_duration.get()
    stats += ' %s runs %s hours' % (runs, hours)
  list_table.append(('Stats', stats))
  for key, value in test_plan.create_job_args.iteritems():
    if key not in ATTRIBUTES:
      list_table.append((key.replace('_', ' ').title(), value))
  list_table.append(('Machines', test_plan.machines))
  return create_list_table_div(list_table)


def create_hosts_list_div(hosts):
  return tag.div(tag.span(tag.b('Total:'), len(hosts), _s=True, _sep=' '),
                 tag.ul(tag.li(class_='hostnames',
                               *[tag.a(host.hostname, _s=True)
                                 for host in hosts])),
                 id='hosts_list_div')


def create_host_display_state(host):
  state = host.state
  if state:
    return tag.span(', '.join(state), class_='host_state', _s=True)
  if host.idle:
    return 'Idle'
  else:
    return 'Busy'


def create_hosts_table_tr(host):
  ATTRIBUTES = ('hostname', 'state', 'status', 'platform', 'labels',
                'protection', 'notes')
  tr = tag.tr
  if not host:
    for attr in ATTRIBUTES:
      tr += tag.th(attr.replace('_', ' ').title(), _s=True)
  else:
    for attr in ATTRIBUTES:
      if attr == 'state':
        value = create_host_display_state(host)
      elif attr == 'labels':
        value = ', '.join([label for label in host.labels
                           if label != host.platform and
                              label != constants.HL_TRIAGE_NEEDED])
      else:
        value = getattr(host, attr)
        if attr == 'hostname':
          value = tag.a(value, _s=True)
        elif attr == 'notes':
          value = cgi.escape(str(value))
      tr += tag.td(value, _s=True)
  return tr


def create_hosts_table(hosts):
  table = tag.table(create_hosts_table_tr(None), id='hosts_table')
  for host in hosts:
    table += create_hosts_table_tr(host)
  return table


def group_hosts(hosts, func):
  host_group_dict = {}
  for host in hosts:
    key = func(host)
    if key:
      host_group_dict.setdefault(key, []).append(host.hostname)
  return host_group_dict


def create_hosts_group_ul(host_group_dict):
  ul = tag.ul
  if host_group_dict:
    for group_key, hostnames in sorted(host_group_dict.iteritems()):
      ul += tag.li(tag.b(cgi.escape(group_key), ':'),
                   len(hostnames), _s=True, _sep=' ')
      hostname_as = [tag.a(hostname, _s=True)
                     for hostname in hostnames]
      ul += tag.li(class_='hostnames', *hostname_as)
  else:
    ul += 'None'
  return ul


def create_hosts_group_by_state_ul(hosts):

  def joined_state(host):
    return ', '.join(host.state)

  return create_hosts_group_ul(group_hosts(hosts, joined_state))


def create_hosts_group_by_labels_ul(hosts):

  def joined_labels(host):
    return ', '.join(sorted(label for label in host.labels
                            if label != constants.HL_TRIAGE_NEEDED))

  return create_hosts_group_ul(group_hosts(hosts, joined_labels))


def create_hosts_group_by_notes_ul(hosts):

  return create_hosts_group_ul(group_hosts(hosts,
                                           operator.attrgetter('notes')))


STATUS_CLASS = {
  'TRIAGE NEEDED': 'triage_needed',
  'TRIAGED': 'triaged',
  'FAIL': 'fail',
  'RESOLVED': 'resolved',
  'GOOD': 'good'
}

RESULTS_COLUMNS = ('PENDING',
                   'RUNNING',
                   'GOOD',
                   'FAIL',
                   'TRIAGE NEEDED',
                   'TRIAGED')

RUNTIME_COLUMNS = ('RUNNING',
                   'GOOD',
                   'FAIL',
                   'TRIAGE NEEDED',
                   'TRIAGED',
                   'RESOLVED')


def create_triage_symptoms_div(runs):
  if isinstance(runs, (list, tuple, types.GeneratorType)):
    ti_dict = {}
    for run in runs:
      triage_info = run.triage_info
      symptoms = run.symptoms
      ti_runs, sym_dict = ti_dict.setdefault(triage_info, ([], {}))
      ti_runs.append(run)
      sym_runs = sym_dict.setdefault(symptoms, [])
      sym_runs.append(run)

    ti_items = [(-len(ti_runs), ti, ti_runs, sym_dict)
                for ti, (ti_runs, sd) in ti_dict.iteritems()]
    ti_items.sort()
    inner_div = tag.div(class_='triage_symptoms_inner_div')
    for ti_count, triage_info, ti_runs, sym_dict in ti_items:
      ti_count = -ti_count
      if not triage_info:
        triage_info = 'None'
      ti_link = tag.a('%s runs' % ti_count,
                      href='/triage?job=%s' % '+'.join(
                          str(run.job_idx) for run in ti_runs))
      inner_div += tag.span(tag.b(ti_link, ':'), cgi.escape(triage_info),
                            _s=True, _sep=' ')
      sym_items = [(-len(sym_runs), sym, sym_runs)
                   for sym, sym_runs in sym_dict.iteritems()]
      sym_items.sort()
      sym_ul = tag.ul
      for sym_count, symptoms, sym_runs in sym_items:
        sym_count = -sym_count
        if not symptoms:
          symptoms = 'None'
        sym_link = tag.a('%s runs' % sym_count,
                         href='/triage?job=%s' % '+'.join(
                             str(run.job_idx) for run in sym_runs))
        sym_ul += tag.li(tag.b(sym_link, ':'),
                         tag.span(cgi.escape(symptoms)),
                         _s=True, _sep=' ')
      inner_div += sym_ul
  else:
    inner_div = tag.div(
        tag.span(cgi.escape(str(runs.triage_info)), _s=True),
        tag.br(_nc=True),
        tag.span(cgi.escape(runs.symptoms), _s=True),
        class_='triage_symtpoms_run_inner_div')

  return tag.div(inner_div, class_='triage_symptoms_div')


def create_stats_table_tr(stats, idx_attr, columns, get_sql_query_conditions,
                          row_header_extra = None):

  def get_sql_and_tko_dargs(status):
    if status == 'RUNNING':
      return {'status': 'RUNNING'}, {
          'filter_0_include': 'false',
          'filter_0_label': constants.TL_RESOLVED,
          'filter_1_include': 'false',
          'filter_1_label': constants.TL_NO_RERUN}
    if status == 'GOOD':
      return {'status': 'GOOD'}, {
          'filter_0_include': 'false',
          'filter_0_label': constants.TL_RESOLVED,
          'filter_1_include': 'false',
          'filter_1_label': constants.TL_NO_RERUN}
    if status == 'TRIAGE NEEDED':
      return {'status__ne': 'GOOD'}, {
          'show_incomplete': 'false',
          'filter_0_include': 'false',
          'filter_0_label': constants.TL_RESOLVED,
          'filter_1_include': 'false',
          'filter_1_label': constants.TL_NO_RERUN,
          'filter_2_include': 'false',
          'filter_2_attribute': "= '%s'" % constants.TA_TRIAGE_INFO,
          'filter_2_value': "!= ''"}
    if status == 'TRIAGED':
      return {'status__ne': 'GOOD'}, {
          'filter_0_include': 'false',
          'filter_0_label': constants.TL_RESOLVED,
          'filter_1_include': 'false',
          'filter_1_label': constants.TL_NO_RERUN,
          'filter_2_include': 'true',
          'filter_2_attribute': "= '%s'" % constants.TA_TRIAGE_INFO,
          'filter_2_value': "!= ''"}
    if status == 'RESOLVED':
      return {'status__ne': 'GOOD',
              'test_label': constants.TL_RESOLVED}, {}
    if status == 'FAIL':
      return {'status__ne': 'GOOD',
              'test_label': constants.TL_NO_RERUN}, {
          'filter_0_include': 'false',
          'filter_0_label': constants.TL_RESOLVED}
    return None, None

  def make_runs_url(runs):
    job_idx_query = url.tko_job_host_runs_sql(
        runs, operator.attrgetter(idx_attr))
    if job_idx_query:
      if ' OR ' in job_idx_query:
        job_idx_query = '(%s)' % job_idx_query
      return url.tko_url(condition=get_sql_query_conditions(job_idx_query))
    return None

  def make_url(sql_dargs={}, tko_dargs={}):
    return url.tko_url(
      condition=get_sql_query_conditions(**sql_dargs),
      **tko_dargs)

  tr = tag.tr
  if not stats:
    th = tag.th(_s=True)
    if row_header_extra:
      th += row_header_extra
    tr += th
    for column in columns:
      tr += tag.th(column, _s=True)
  else:
    th = tag.th
    text = cgi.escape(stats.status_pformat(None))
    if stats.runs:
      th += tag.a(text, href=make_runs_url(stats.runs), _s=True)
    else:
      th += tag.span(text, _s=True)
    th += tag.sup(tag.a('*', href=make_url(), class_='star'), _s=True)
    if row_header_extra:
      th += row_header_extra
    tr += th

    for column in columns:
      td = tag.td
      total_count, runs = stats.get(column)
      text = cgi.escape(stats.status_pformat(column))
      class_ = STATUS_CLASS.get(column)
      if runs:
        a = tag.a(text, href=make_runs_url(runs), _s=True)
        if class_:
          a['class_'] = class_
        td += a
      else:
        td += text

      sql_dargs, tko_dargs = get_sql_and_tko_dargs(column)
      if sql_dargs is not None and tko_dargs is not None:
        a = tag.a('*', href=make_url(sql_dargs, tko_dargs), class_='star')
        if runs and class_:
          a['class_'] += ' %s' % class_;
        td += tag.sup(a, _s=True)

      if runs and column in ('FAIL', 'TRIAGE NEEDED', 'TRIAGED', 'RESOLVED'):
        td += create_triage_symptoms_div(runs)

      tr += td
  return tr


def create_overall_results_table(overall_stats, get_sql_query_conditions):
  table = tag.table(class_='stats_table', id='overall_results_table')
  table += create_stats_table_tr(None, 'job_idx_idx', RESULTS_COLUMNS,
                                 get_sql_query_conditions)
  table += create_stats_table_tr(overall_stats,
                                 'job_idx_idx',
                                 RESULTS_COLUMNS,
                                 get_sql_query_conditions)
  return table


def create_tests_results_table(test_stats, tests,
                               get_sql_query_conditions):

  def get_sql_query_conditions_with_test(*args, **dargs):
    return get_sql_query_conditions(
        "job_name LIKE '%%: %s'" % test.job_name, *args, **dargs)

  table = tag.table(class_='stats_table', id='tests_results_table')
  table += create_stats_table_tr(None, 'test_job_idx_idx', RESULTS_COLUMNS,
                                 get_sql_query_conditions)
  for test in tests:
    tr = create_stats_table_tr(test_stats[test.job_name],
                               'test_job_idx_idx',
                               RESULTS_COLUMNS,
                               get_sql_query_conditions_with_test,
                               '%sh' % test.duration)
    table += tr
  return table


def create_hosts_results_table(host_stats, hosts,
                               get_sql_query_conditions):

  def get_sql_query_conditions_with_host(*args, **dargs):
    return get_sql_query_conditions(
        "hostname = '%s'" % host.hostname, *args, **dargs)

  table = tag.table(class_='stats_table', id='hosts_results_table')
  table += create_stats_table_tr(None, 'host_job_idx_idx', RESULTS_COLUMNS,
                                 get_sql_query_conditions)
  for host in hosts:
    tr = create_stats_table_tr(host_stats[host.hostname],
                               'host_job_idx_idx',
                               RESULTS_COLUMNS,
                               get_sql_query_conditions_with_host,
                               ' - %s' % create_host_display_state(host))
    if host.notes:
      tr[0][0]['title'] = cgi.escape(host.notes, True)
    table += tr
  return table


def create_overall_runtime_table(overall_run_stats, get_sql_query_conditions):
  table = tag.table(class_='stats_table', id='overall_runtime_table')
  table += create_stats_table_tr(None, 'job_idx_idx', RUNTIME_COLUMNS,
                                 get_sql_query_conditions)
  table += create_stats_table_tr(overall_run_stats,
                                 'job_idx_idx',
                                 RUNTIME_COLUMNS,
                                 get_sql_query_conditions)
  return table


def create_tests_runtime_table(test_run_stats, tests,
                               get_sql_query_conditions):

  def get_sql_query_conditions_with_test(*args, **dargs):
    return get_sql_query_conditions(
        "job_name LIKE '%%: %s'" % test.job_name, *args, **dargs)

  table = tag.table(class_='stats_table', id='tests_runtime_table')
  table += create_stats_table_tr(None, 'test_job_idx_idx', RUNTIME_COLUMNS,
                                 get_sql_query_conditions)
  for test in tests:
    tr = create_stats_table_tr(
        test_run_stats.get(test.job_name,
                           test_stats_module.TestStats(test.job_name)),
        'test_job_idx_idx',
        RUNTIME_COLUMNS,
        get_sql_query_conditions_with_test,
        '%sh' % test.duration)
    table += tr
  return table


def create_hosts_runtime_table(host_run_stats, hosts,
                               get_sql_query_conditions):

  def get_sql_query_conditions_with_host(*args, **dargs):
    return get_sql_query_conditions(
        "hostname = '%s'" % host.hostname, *args, **dargs)

  table = tag.table(class_='stats_table', id='hosts_runtime_table')
  table += create_stats_table_tr(None, 'host_job_idx_idx', RUNTIME_COLUMNS,
                                 get_sql_query_conditions)
  for host in hosts:
    tr = create_stats_table_tr(
        host_run_stats.get(host.hostname,
                           test_stats_module.TestStats(host.hostname)),
        'host_job_idx_idx',
        RUNTIME_COLUMNS,
        get_sql_query_conditions_with_host,
        ' - %s' % create_host_display_state(host))
    if host.notes:
      tr[0][0]['title'] = cgi.escape(host.notes, True)
    table += tr
  return table


def create_status_table_tr(host, tests, host_job_status):
  tr = tag.tr
  if not host:
    tr += tag.th(_s=True)
    for test in tests:
      tr += tag.th(cgi.escape(test.job_name), _s=True)
  else:
    span = tag.span(host.hostname)
    if host.notes:
      span['title'] = cgi.escape(host.notes, True)
    tr += tag.th(span, ' - %s' % create_host_display_state(host), _s=True)
    for test in tests:
      status, run = host_job_status[host.hostname][test.job_name]
      if run:
        run_time, queued_time = run.running_time
        hr_run_time = utils.human_time_span(run_time)
        hr_queued_time = utils.human_time_span(queued_time)
        a = tag.a('%s (%s, %s)' % (status, hr_run_time, hr_queued_time),
                  title=run.job_tag, _s=True)
        class_ = STATUS_CLASS.get(status)
        if status == 'RUNNING' and (
            run_time > (test.duration + 1) * 60 * 60 or
            queued_time - run_time > 30 * 60):
          class_ = 'overtime'
        if class_:
          a['class_'] = class_
        tr += tag.td(a, create_triage_symptoms_div(run))
      else:
        tr += tag.td(status, _s=True)

  return tr


def create_status_table(hosts, tests, host_job_status):
  table = tag.table(id='status_table')
  table += create_status_table_tr(None, tests, host_job_status)
  for host in hosts:
    table += create_status_table_tr(host, tests, host_job_status)
  return table


def create_test_views_table_tr(test_view, labels=()):
  ATTRIBUTES = ('test_idx', 'test_name', 'test_started_time',
                'test_finished_time', 'status', 'labels', 'reason')
  tr = tag.tr
  if not test_view:
    for attr in ATTRIBUTES:
      tr += tag.th(attr.replace('_', ' ').title(), _s=True)
  else:
    for attr in ATTRIBUTES:
      if attr == 'labels':
        value = ', '.join(sorted(labels))
      else:
        value = getattr(test_view, attr)
      if attr == 'test_idx':
        value = tag.a(value, _s=True)
      tr += tag.td(value, _s=True)
  return tr


def create_test_views_table(job_host_run):
  table = tag.table(create_test_views_table_tr(None),
                    class_='test_views_table')
  for test_view in job_host_run.test_views or ():
    table += create_test_views_table_tr(
        test_view, job_host_run.get_test_labels(test_view))
  return table


def create_job_host_run_list_table(job_host_run, duration):
  ATTRIBUTES = ('job_idx', 'job_tag', 'job_name', 'job_owner',
                'job_queued_time', 'job_started_time', 'job_finished_time',
                'running_time', 'status', 'symptoms', 'triage_info')
  list_table = []
  for attr in ATTRIBUTES:
    value = getattr(job_host_run, attr)
    if attr == 'running_time':
      run_time, queued_time = value
      value = ', '.join(utils.human_time_span(t) for t in value)
      if (run_time > (duration + 1) * 60 * 60 or
          queued_time - run_time > 30 * 60):
        value = tag.span(value, class_='overtime')
    elif attr == 'status':
      class_ = STATUS_CLASS.get(value)
      if class_:
        value = tag.span(value, class_=class_)
    elif attr == 'triage_info':
      if value is None:
        value = ''
    elif attr == 'job_idx' or attr == 'job_tag':
      value = tag.a(value, _s=True)
    list_table.append((attr.replace('_', ' ').title(), value))
  div = create_list_table_div(list_table)
  div['class_'] += ' job_host_run_list_table'
  return div


def create_job_host_runs_table_tr(job_host_run, duration):
  ATTRIBUTES = ('job_idx', 'job_tag', 'job_name', 'job_queued_time',
                'running_time', 'status', 'symptoms', 'triage_info')
  tr = tag.tr
  if not job_host_run:
    for attr in ATTRIBUTES:
      tr += tag.th(attr.replace('_', ' ').title(), _s=True)
  else:
    for attr in ATTRIBUTES:
      value = getattr(job_host_run, attr)
      if attr == 'running_time':
        run_time, queued_time = value
        value = ', '.join(utils.human_time_span(t) for t in value)
        if (run_time > (duration + 1) * 60 * 60 or
            queued_time - run_time > 30 * 60):
          value = tag.span(value, class_='overtime')
      elif attr == 'status':
        class_ = STATUS_CLASS.get(value)
        if class_:
          value = tag.span(value, class_=class_)
      elif attr == 'triage_info':
        if value is None:
          value = ''
      elif attr == 'job_idx' or attr == 'job_tag':
        value = tag.a(value, _s=True)
      tr += tag.td(value, _s=True)
  return tr


def create_job_host_runs_table(job_host_runs, job_name_to_test):
  table = tag.table(create_job_host_runs_table_tr(None, 0),
                    class_='job_host_runs_table')
  for job_host_run in job_host_runs:
    table += create_job_host_runs_table_tr(
        job_host_run,
        job_name_to_test[job_host_run.test_job_name].duration)
  return table


def create_page_links_span(base_url, length, offset, limit, extra=''):
  if offset < 0 or offset >= length:
    offset = 0
  if limit < 0:
    limit = 20
  end = offset + limit
  if end > length:
    end = length

  FIRST_MSG = cgi.escape('<< First')
  PREVIOUS_MSG = cgi.escape('< Previous')
  NEXT_MSG = cgi.escape('> Next')
  LAST_MSG = cgi.escape('>> Last')

  span = tag.span
  if offset:
    first = tag.a(FIRST_MSG,
                  href='%soffset=0&limit=%d%s' % (base_url, limit, extra))
    previous = tag.a(PREVIOUS_MSG,
                     href='%soffset=%d&limit=%d%s' % (
                         base_url, max(offset - limit, 0), limit, extra))
  else:
    first = FIRST_MSG
    previous = PREVIOUS_MSG
  span += tag.span(first, class_='page_links', _s=True)
  span += tag.span(previous, class_='page_links', _s=True)

  if length:
    content = '%d - %d of %d' % (offset + 1, end, length)
  else:
    content = '0 - 0 of 0'
  span += tag.span(content, class_='page_pos', _s=True)

  if end < length:
    next = tag.a(NEXT_MSG,
                 href='%soffset=%d&limit=%d%s' % (base_url, end, limit,
                                                  extra))
    last = tag.a(LAST_MSG,
                 href='%soffset=%d&limit=%d%s' % (
                     base_url, length - limit, limit, extra))
  else:
    next = NEXT_MSG
    last = LAST_MSG
  span += tag.span(next, class_='page_links', _s=True)
  span += tag.span(last, class_='page_links', _s=True)
  return span


def create_table_with_page_links_table(contents, offset, limit, base_url,
                                       create_table, extra=''):
  table = tag.table(class_='page_links_table')
  links_span = create_page_links_span(base_url, len(contents), offset, limit,
                                      extra)
  table += tag.tr(tag.td(links_span, align='center'))
  table += tag.tr(tag.td(create_table(contents[offset: offset + limit])))
  table += tag.tr(tag.td(links_span, align='center'))
  return table


def create_html(handler, title, contents):
  head = tag.head(tag.title(title, _s=True),
                  tag.link(rel='stylesheet', type='text/css',
                           href='/resources/dioxide.css',
                           _nc=True))
  if os.path.isfile(os.path.join(os.path.dirname(__file__),
                                 'resources/site_dioxide.css')):
    head += tag.link(rel='stylesheet', type='text/css',
                     href='/resources/site_dioxide.css',
                     _nc=True)
  head += tag.script("var autotest_web = '%s';" % rpc_stubs.AUTOTEST_WEB,
                     'var super_user = %s;' % (
                         handler.localhost and 'true' or 'false'),
                     type='text/javascript')
  for script in ('utility', 'dioxide'):
    head += tag.script(type='text/javascript',
                       src='/resources/%s.js' % script,
                       _s=True)
    if os.path.isfile(os.path.join(os.path.dirname(__file__),
                                   'resources/site_%s.js' % script)):
      head += tag.script(type='text/javascript',
                         src='/resources/site_%s.js' % script,
                         _s=True)

  header = tag.div(tag.h1(title), id='header', _s=True)
  tr = tag.tr(tag.td('Page Generated: ',
                     tag.i(time.ctime()),
                     id='page_generated_time',
                     _s=True))
  if handler.localhost:
    tr += tag.td(tag.a('super user', href='/reload', title='click to reload'),
                 id='super_user', _s=True)
  tr += tag.td('Server Started: ',
               tag.i(handler.server.started_time),
               id='server_started_time',
               _s=True)
  footer = tag.div(tag.hr(_nc=True),
                   tag.table(tr, width='100%'), id='footer')
  body = tag.body(
      tag.script(type='text/javascript', src='/resources/wz_tooltip.js',
                 _s=True),
      header,
      *contents)
  body += footer

  return tag.html(head, body)


utils.import_site(globals())
